/*
 * @time 2018-2-13
 * @author dhclly
 * @desc 根据javascript精粹一书对js进行做的扩展
 */

//############################################################
//Function构造函数的扩展

/*
 * 给所有的构造函数(包括Object)添加一个添加子实例方法的方法。
 * 如String.prototype.getFirstChar=func可以写成String.addMethod('getFirstChar',func),
 * 由此可以获得更好的可读性
 */
if(typeof Function.prototype.addMethod !== "function") {
	Function.prototype.addMethod = function(name, func) {
		if(this.prototype[name]) return;
		this.prototype[name] = func;
		return this;
	}
}

Function.addMethod("curry", function() {
	var slice = Array.prototype.slice,
		args = slice.apply(arguments),
		that = this;
	return function() {
		return that.apply(null, args.concat(slice.apply(arguments)));
	};
});
//############################################################
//Object构造函数的扩展

//基于一个对象为原型对象进行继承（形成原型链）生成一个新对象
if(typeof Object.extend !== "function") {
	if(Object.create) {
		Object.extend = Object.create;
	} else {
		Object.extend = function(obj) {
			var F = function() {};
			F.prototype = obj;
			return new F();
		}
	}
}

//获取父级对象
if(typeof Object.superior !== "function") {
	Object.addMethod('superior', function(name) {
		var that = this;
		var method = that[name];
		return function() {
			return method.apply(that, arguments);
		}
	})
}

//############################################################
//Number构造函数的扩展

//扩展Number类，获取数字类型的整数部分
Number.addMethod("getInteger", function() {
	var v = this.valueOf();
	return Math[v ? 'ceil' : 'floor'](v);
});

//扩展Number类，判断数字是否是浮点数
Number.addMethod("isFloat", function() {
	return this.toString().indexOf(".") > 0;
});

//静态方法版本
Number.getInteger = function(num) {
	if(typeof num !== "number") {
		throw new TypeError("please pass a number");
	}
	return Math[num < 0 ? 'ceil' : 'floor'](num);
}
Number.isFloat = function(num) {
	if(typeof num !== "number") {
		throw new TypeError("please pass a number");
	}
	return num.toString().indexOf(".") > 0;
}

//############################################################
//String构造函数的扩展

String.addMethod("trimLeft", function() {
	return this.replace(/^\s+/g, '');
})
String.addMethod("trimRight", function() {
	return this.replace(/\s+$/g, '');
})
String.addMethod("trim", function() {
	return this.replace(/^\s+|\s+$/g, '');
	//return this.trimLeft().trimRight();
});
//转换字符实体为字符
String.addMethod("deentityify", function() {
	var entities = {
		quot: '"',
		lt: '<',
		gt: '>'
	};
	return function() {
		return this.replace(/&([^&;]+);/g, function(a, b) {
			timer += 1;
			var r = entities[b];
			return typeof r === 'string' ? r : a;
		})
	}
}());

//############################################################
//Math构造函数的扩展
Math.randomByRange=function (min,max) {
	if(!min){
		min=0;
	}
	if(!max){
		max=1;
	}
	return Math.random()*max+min;
}
//############################################################
//遍历dom
var walkTheDOM = function walk(node, func) {
	func(node);
	node = node.firstChild;
	while(node) {
		walk(node, func);
		node = node.nextSibling;
	}
}

//通过属性获取dom
var getElementsByAttribute = function(attr, value) {
	var results = [];
	walkTheDOM(document.body, function(node) {
		var actual = node.nodeType === 1 && node.getAttribute(attr);
		if(typeof actual === 'string' && (actual === value || typeof value !== 'string')) {
			results.push(node);
		}
	})
	return results;
}


//计数器
var numTimer = function() {
	var val = 0;
	return {
		increment: (inc) => val += typeof inc === 'number' ? inc : 1,
		getVal: () => val
	}
}

var quo = function(status) {
	return {
		getStatus: function() {
			return status;
		}
	}
}



//通过
var alertTheOrderNumber = function(nodelist) {
	var i
	for(i = 0; i < nodelist.length; i += 1) {
		nodelist[i].onclick = function(i) {
			return function() {
				alert("the order number is " + i);
			}
		}(i);
	}
}
//序列号生成器
var serialMaker = function() {
	var prefix = '',
		seq = 0;
	return {
		setPrefix: function(p) {
			prefix = String(p);
		},
		setSeq: function(s) {
			seq = s;
		},
		gensym: function() {
			var result = prefix + seq;
			seq += 1;
			return result;
		}
	};
};

var fibonacci = function() {
	var cache = [0, 1];
	var fib = function(n) {
		var result = cache[n];
		if(typeof result !== 'number') {
			result = fib(n - 1) + fib[n - 2];
			cache[n] = result;
		}
		return result;
	}
	return fib;
}();

var memoizer = function(memo, fundamental) {
	var shell = function(n) {
		var result = memo[n];
		if(typeof result !== 'number') {
			result = fundamental(shell, n);
			memo[n] = result;
		}
		return result;
	};
	return shell;
};

var fibonacciV2 = memoizer([0, 1], function(shell, n) {
	return shell(n - 1) + shell(n - 2);
});
var factorial = memoizer([1, 1], function(shell, n) {
	return n * shell(n - 1);
})

//############################################################
//说明

var myMammal = {
	name: 'herb the mamal',
	getName: function() {
		return this.name;
	},
	says: function() {
		return this.saying || '';
	}
}

var myCat = Object.extend(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.purr = function(n) {
	var i, s = '';
	for(i = 0; i < n; i++) {
		if(s) {
			s += '-';
		}
		s += 'r';
	}
	return s;
}
myCat.getName = function() {
	return this.says() + ' ' + this.name + ' ' + this.says();
}

var block = function() {
	var oldScope = scope;
	scope = Object.extend(scope);
	advance('{');
	parse(scope);
	advance('}');
	scope = oldScope;
}

var mammal = function(spec) {
	var that = {};
	that.getName = function() {
		return spec.name;
	}
	that.says = function() {
		return spec.saying || '';
	}
	return that;
}

var myMammal2 = mammal({
	name: 'Herb',
	saying: 'hello'
});

var cat = function(spec) {
	spec.saying = spec.saying || 'meow';
	var that = mammal(spec);
	that.purr = function(n) {
		var i, s = '';
		for(i = 0; i < n; i++) {
			if(s) {
				s += '-';
			}
			s += 'r';
		}
		return s;
	}
	that.getName = function() {
		return that.says() + ' ' + spec.name + ' ' + that.says();
	}
	return that;
}
var myCat2 = cat({
	name: 'deck'
});
var coolcat = function(spec) {
	var that = cat(spec);
	var superGetName = that.superior('getName');
	that.getName = function(n) {
		return 'like ' + superGetName() + ' baby';
	};
	return that;
};
var myCat3 = coolcat({
	name: 'coolcat Bix'
});